package org.codersunit.radboid.data;

import java.util.Calendar;
import java.util.Comparator;
import java.util.GregorianCalendar;

public class DateComparator implements Comparator<Calendar> {
	protected static final long MILLISECS_PER_SECOND = 1000;
    protected static final long MILLISECS_PER_MINUTE = 60 * MILLISECS_PER_SECOND;
    protected static final long MILLISECS_PER_HOUR = 60 * MILLISECS_PER_MINUTE;
    protected static final long MILLISECS_PER_DAY = 24 * MILLISECS_PER_HOUR;
    protected static final int DAYS_PER_WEEK = 7;
	
	private int p;
	
	public DateComparator() {
		this(Schedule.DAILY);
	}
	
	/**
	 * @param period One of Schedule.DAILY, Schedule.WEEKLY, Schedule.MONTHLY or Schedule.YEARLY
	 */
	public DateComparator(int period) {
		p = period;
	}
	
	@Override
	public int compare(Calendar first, Calendar second) {
		final int firstYear = first.get(Calendar.YEAR);
		final int secondYear = second.get(Calendar.YEAR);
		switch(p) {
		case Schedule.DAILY:
			final int firstDay = first.get(Calendar.DAY_OF_YEAR);
			final int secondDay = second.get(Calendar.DAY_OF_YEAR);
			
			if(firstYear == secondYear && firstDay == secondDay) {
				return 0;
			} else if(firstYear == secondYear) {
				return firstDay < secondDay ? -1 : 1;
			} else {
				return firstYear < secondYear ? -1 : 1;
			}
		case Schedule.WEEKLY:
			final int firstWeek = first.get(Calendar.WEEK_OF_YEAR);
			final int secondWeek = second.get(Calendar.WEEK_OF_YEAR);
			if(firstYear == secondYear && firstWeek == secondWeek) {
				return 0;
			} else if(firstYear == secondYear) {
				return firstWeek < secondWeek ? -1 : 1;
			} else {
				return firstYear < secondYear ? -1 : 1;
			}
		case Schedule.MONTHLY:
			final int firstMonth = first.get(Calendar.MONTH);
			final int secondMonth = second.get(Calendar.MONTH);
			if(firstYear == secondYear && firstMonth == secondMonth) {
				return 0;
			} else if(firstYear == secondYear) {
				return firstMonth < secondMonth ? -1 : 1;
			} else {
				return firstYear < secondYear ? -1 : 1;
			}
		case Schedule.YEARLY:
			if(firstYear == secondYear) {
				return 0;
			} else {
				return firstYear < secondYear ? -1 : 1;
			}
		}
		return 0;
	}
	
	public int getDifferenceInDays(Calendar first, Calendar second) {
		long firstL = first.getTimeInMillis() + first.getTimeZone().getOffset(first.getTimeInMillis());
		long secondL = second.getTimeInMillis() + second.getTimeZone().getOffset(second.getTimeInMillis());
		
		return (int)((firstL - secondL) / MILLISECS_PER_DAY);
	}
	
	public int getDifferenceInMonths(Calendar first, Calendar second) {
		int sign = first.before(second) ? -1 : 1;
		int diff = 0;
		int firstYear = first.get(Calendar.YEAR);
		int firstMonth = first.get(Calendar.MONTH);
		
		Calendar temp = new GregorianCalendar();
		temp.setTime(second.getTime());
		
		while(firstYear != temp.get(Calendar.YEAR) ||
				firstMonth != temp.get(Calendar.MONTH)) {
			temp.add(Calendar.MONTH, sign);
			diff += sign;
		}
		return diff;
	}
	
	public int getDifferenceInYears(Calendar first, Calendar second) {
		return first.get(Calendar.YEAR) - second.get(Calendar.YEAR);
	}
	
	public int getDifferenceInWeeks(Calendar first, Calendar second) {
		return getDifferenceInDays(first, second) / DAYS_PER_WEEK;
	}
	
	public long getDifferenceInSeconds(Calendar first, Calendar second) {
		long firstL = first.getTimeInMillis() + first.getTimeZone().getOffset(first.getTimeInMillis());
		long secondL = second.getTimeInMillis() + second.getTimeZone().getOffset(second.getTimeInMillis());
		
		return (firstL - secondL) / MILLISECS_PER_SECOND;
	}
}
